<?php

namespace App\Services\Bank;

use Carbon\Carbon;
use Illuminate\Support\Facades\Log;

class BankApiService
{
    private BankApiClient $client;

    public function __construct(BankApiClient $client)
    {
        $this->client = $client;
    }

    /**
     * 联行号增量同步 (BY0012)
     * 
     * @param string $queryDate 同步日期 (yyyy-MM-dd)
     * @return array
     */
    public function syncBankNumbers(string $queryDate): array
    {
        Log::info('Starting bank numbers sync', [
            'operation' => 'SYNC_BANK_NUMBERS',
            'query_date' => $queryDate,
        ]);

        $mapData = [
            'queryDate' => $queryDate,
        ];

        $result = $this->client->callApi('BANK_SYNC', $mapData);
        
        if ($result['success']) {
            Log::info('Bank numbers sync completed successfully', [
                'operation' => 'SYNC_BANK_NUMBERS',
                'query_date' => $queryDate,
                'count' => count($result['loop_data']),
                'ret_code' => $result['ret_code'],
            ]);
        } else {
            Log::warning('Bank numbers sync failed', [
                'operation' => 'SYNC_BANK_NUMBERS',
                'query_date' => $queryDate,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);
        }

        return $result;
    }

    /**
     * 联行号查询 (BY0004)
     * 
     * @param string $bankName 行名关键字 (必填)
     * @param string|null $bankTypeName 行类型名称 (选填)
     * @param string|null $isPreciseQuery 是否精确查询 (1-精确，0-模糊，默认模糊)
     * @return array
     */
    public function queryBankNumbers(string $bankName, ?string $bankTypeName = null, ?string $isPreciseQuery = '0'): array
    {
        $mapData = [
            'bankName' => $bankName,
        ];

        if ($bankTypeName !== null) {
            $mapData['bankTypeName'] = $bankTypeName;
        }

        if ($isPreciseQuery !== null) {
            $mapData['isPreciseQuery'] = $isPreciseQuery;
        }

        Log::info('Starting bank numbers query', [
            'operation' => 'QUERY_BANK_NUMBERS',
            'bank_name' => $bankName,
            'bank_type_name' => $bankTypeName,
            'is_precise_query' => $isPreciseQuery,
        ]);

        $result = $this->client->callApi('BANK_QUERY', $mapData);
        
        if ($result['success']) {
            Log::info('Bank numbers query completed successfully', [
                'operation' => 'QUERY_BANK_NUMBERS',
                'bank_name' => $bankName,
                'bank_type_name' => $bankTypeName,
                'count' => count($result['loop_data']),
                'ret_code' => $result['ret_code'],
            ]);
        } else {
            Log::warning('Bank numbers query failed', [
                'operation' => 'QUERY_BANK_NUMBERS',
                'bank_name' => $bankName,
                'bank_type_name' => $bankTypeName,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);
        }

        return $result;
    }

    /**
     * 余额查询 (BY0007)
     */
    public function queryBalance(string $bankAcc): array
    {
        $bankAcc = trim($bankAcc);
        if ($bankAcc === '') {
            throw new \InvalidArgumentException('银行账号不能为空');
        }

        Log::info('Starting balance query', [
            'operation' => 'BALANCE_QUERY',
            'bank_acc' => $bankAcc,
        ]);

        $result = $this->client->callApi('BALANCE_QUERY', [], [
            ['bankAcc' => $bankAcc],
        ]);

        if (!$result['success']) {
            Log::warning('Balance query failed', [
                'operation' => 'BALANCE_QUERY',
                'bank_acc' => $bankAcc,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);

            throw new \RuntimeException($result['ret_msg'] ?? '余额查询失败');
        }

        $balances = $this->extractBalances($result);

        Log::info('Balance query completed successfully', [
            'operation' => 'BALANCE_QUERY',
            'bank_acc' => $bankAcc,
            'balance' => $balances['balance'],
            'available_balance' => $balances['available_balance'],
            'ret_code' => $result['ret_code'],
        ]);

        return $balances;
    }

    private function extractBalances(array $result): array
    {
        $row = $result['loop_data'][0] ?? [];

        $balance = $this->toAmount($row['bankBal'] ?? null);
        $available = $this->toAmount($row['availBal'] ?? null);

        return [
            'balance' => $balance,
            'available_balance' => $available,
        ];
    }

    private function toAmount($value): ?float
    {
        if ($value === null) {
            return null;
        }

        if (is_string($value)) {
            $value = str_replace(',', '', $value);
        }

        return is_numeric($value) ? (float) $value : null;
    }

    /**
     * 批量代发 (BY0008)
     * 
     * @param string $erpBatchNo ERP批次号 (必填，保证唯一)
     * @param string $wageTitle 发放标题 (必填)
     * @param string $busiType 发放业务类型 (必填: 1-工资, 2-股权基金分红, 3-其他)
     * @param array $payDetails 付款明细数组
     * @param array $options 其他选项
     * @return array
     */
    public function batchPay(string $erpBatchNo, string $wageTitle, string $busiType, array $payDetails, array $options = []): array
    {
        // 计算总金额和总笔数
        $totalMoney = number_format(array_sum(array_column($payDetails, 'amt')), 2, '.', '');
        $totalCount = count($payDetails);
        
        $mapData = [
            'erpBatchNo' => $erpBatchNo,
            'wageTitle' => $wageTitle,
            'busiType' => $busiType,
            'totalMoney' => $totalMoney,
            'totalCount' => $totalCount,
        ];

        // 设置可选参数
        $optionalFields = [
            'payerAccNo', 'payerCorpCode', 'payerCorpName', 'erpPayerCorpCode',
            'payFlow', 'rmk', 'showDetail', 'erpReqUser'
        ];

        foreach ($optionalFields as $field) {
            if (isset($options[$field])) {
                $mapData[$field] = $options[$field];
            }
        }

        // 设置默认值
        $mapData['payFlow'] = $mapData['payFlow'] ?? '1'; // 默认待审批
        $mapData['showDetail'] = $mapData['showDetail'] ?? '1'; // 默认显示
        
        // 设置默认付款人信息（如果未提供）
        if (empty($mapData['payerCorpCode']) && empty($mapData['payerCorpName']) && empty($mapData['erpPayerCorpCode'])) {
            $mapData['payerCorpName'] = config('bank.payer_corp_name');
            $mapData['payerCorpCode'] = config('bank.payer_corp_code');
        }
        
        // 设置默认付款账号（如果未提供）
        if (empty($mapData['payerAccNo'])) {
            $mapData['payerAccNo'] = config('bank.payer_acc_no');
        }

        Log::info('Starting batch pay submission', [
            'operation' => 'BATCH_PAY',
            'erp_batch_no' => $erpBatchNo,
            'wage_title' => $wageTitle,
            'busi_type' => $busiType,
            'detail_count' => count($payDetails),
            'pay_flow' => $mapData['payFlow'],
        ]);

        $result = $this->client->callApi('BATCH_PAY', $mapData, $payDetails);
        
        if ($result['success']) {
            Log::info('Batch pay submitted successfully', [
                'operation' => 'BATCH_PAY',
                'erp_batch_no' => $erpBatchNo,
                'wage_title' => $wageTitle,
                'detail_count' => count($payDetails),
                'ret_code' => $result['ret_code'],
                'batch_no' => $result['map_data']['batchNo'] ?? null,
            ]);
        } else {
            Log::error('Batch pay submission failed', [
                'operation' => 'BATCH_PAY',
                'erp_batch_no' => $erpBatchNo,
                'wage_title' => $wageTitle,
                'detail_count' => count($payDetails),
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);
        }

        return $result;
    }

    /**
     * 代发结果查询 (BY0009)
     * 
     * @param string|null $erpBatchNo ERP批次号
     * @param string|null $startDate 开始日期 (yyyy-MM-dd)
     * @param string|null $endDate 结束日期 (yyyy-MM-dd)
     * @return array
     */
    public function queryPayResult(?string $erpBatchNo = null, ?string $startDate = null, ?string $endDate = null): array
    {
        $mapData = [];

        if ($erpBatchNo !== null) {
            $mapData['erpBatchNo'] = $erpBatchNo;
        }

        if ($startDate !== null) {
            $mapData['startDate'] = $startDate;
        }

        if ($endDate !== null) {
            $mapData['endDate'] = $endDate;
        }

        Log::info('Starting pay result query', [
            'operation' => 'QUERY_PAY_RESULT',
            'erp_batch_no' => $erpBatchNo,
            'start_date' => $startDate,
            'end_date' => $endDate,
        ]);

        $result = $this->client->callApi('PAY_RESULT_QUERY', $mapData);
        
        if ($result['success']) {
            Log::info('Pay result query completed successfully', [
                'operation' => 'QUERY_PAY_RESULT',
                'erp_batch_no' => $erpBatchNo,
                'start_date' => $startDate,
                'end_date' => $endDate,
                'count' => count($result['loop_data']),
                'ret_code' => $result['ret_code'],
            ]);
        } else {
            Log::warning('Pay result query failed', [
                'operation' => 'QUERY_PAY_RESULT',
                'erp_batch_no' => $erpBatchNo,
                'start_date' => $startDate,
                'end_date' => $endDate,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);
        }

        return $result;
    }

    /**
     * 回单批量申请 (BY0010)
     * 
     * @param array $receiptRequests 回单申请数组
     * @return array
     */
    public function batchApplyReceipt(string $compFlowNo, string $beginDate, string $endDate, array $bankAccounts): array
    {
        $bankAccounts = array_values(array_filter(array_map('trim', $bankAccounts), static fn ($acc) => $acc !== ''));

        if (empty($bankAccounts)) {
            throw new \InvalidArgumentException('银行账号列表不能为空');
        }

        $mapData = [
            'compFlowNo' => $compFlowNo,
            'beginDate' => $beginDate,
            'endDate' => $endDate,
        ];

        $loopData = array_map(static fn (string $acc) => ['bankAcc' => $acc], $bankAccounts);

        Log::info('Starting batch receipt application', [
            'operation' => 'BATCH_APPLY_RECEIPT',
            'comp_flow_no' => $compFlowNo,
            'begin_date' => $beginDate,
            'end_date' => $endDate,
            'bank_accounts' => $bankAccounts,
        ]);

        $result = $this->client->callApi('RECEIPT_BATCH_APPLY', $mapData, $loopData);
        
        if ($result['success']) {
            Log::info('Batch receipt application completed successfully', [
                'operation' => 'BATCH_APPLY_RECEIPT',
                'comp_flow_no' => $compFlowNo,
                'begin_date' => $beginDate,
                'end_date' => $endDate,
                'ret_code' => $result['ret_code'],
            ]);
        } else {
            Log::warning('Batch receipt application failed', [
                'operation' => 'BATCH_APPLY_RECEIPT',
                'comp_flow_no' => $compFlowNo,
                'begin_date' => $beginDate,
                'end_date' => $endDate,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);
        }

        return $result;
    }

    /**
     * 单笔回单下载 (BY0066)
     * 
     * @param string $receiptNo 回单号
     * @return array
     */
    public function downloadSingleReceipt(string $receiptNo): array
    {
        $mapData = [
            'receiptNo' => $receiptNo,
        ];

        Log::info('Starting single receipt download', [
            'operation' => 'DOWNLOAD_SINGLE_RECEIPT',
            'receipt_no' => $receiptNo,
        ]);

        $result = $this->client->callApi('RECEIPT_DOWNLOAD', $mapData);
        
        if ($result['success']) {
            Log::info('Single receipt download completed successfully', [
                'operation' => 'DOWNLOAD_SINGLE_RECEIPT',
                'receipt_no' => $receiptNo,
                'ret_code' => $result['ret_code'],
                'has_receipt_data' => !empty($result['map_data']['receiptData']),
            ]);
        } else {
            Log::warning('Single receipt download failed', [
                'operation' => 'DOWNLOAD_SINGLE_RECEIPT',
                'receipt_no' => $receiptNo,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);
        }

        return $result;
    }

    /**
     * 获取昨天的日期字符串 (用于联行号同步)
     * 
     * @return string
     */
    public function getYesterdayDateString(): string
    {
        return Carbon::yesterday()->format('Y-m-d');
    }

    /**
     * 格式化日期为银行API要求的格式
     * 
     * @param Carbon|string $date
     * @return string
     */
    public function formatDate($date): string
    {
        if ($date instanceof Carbon) {
            return $date->format('Y-m-d');
        }
        
        return Carbon::parse($date)->format('Y-m-d');
    }

    /**
     * 验证批量代发明细数据格式
     * 
     * @param array $payDetails
     * @return array 返回验证结果和错误信息
     */
    public function validatePayDetails(array $payDetails): array
    {
        $errors = [];
        
        foreach ($payDetails as $index => $detail) {
            // 验证银行API必填字段
            $requiredFields = ['empNo', 'userName', 'bankAcc', 'amt', 'purpose'];
            
            foreach ($requiredFields as $field) {
                if (!isset($detail[$field]) || empty($detail[$field])) {
                    $errors[] = "明细 {$index}: 字段 {$field} 为必填项";
                }
            }
            
            // 验证金额格式
            if (isset($detail['amt'])) {
                if (!is_numeric($detail['amt']) || $detail['amt'] <= 0) {
                    $errors[] = "明细 {$index}: 金额必须为正数";
                }
            }
        }
        
        return [
            'valid' => empty($errors),
            'errors' => $errors,
        ];
    }

    /**
     * 当日明细查询 (BY0005)
     *
     * @param string $bankAcc 待查询账号 (必填)
     * @param float|null $queryAmtBegin 金额范围起 (选填)
     * @param float|null $queryAmtEnd 金额范围止 (选填)
     * @param string|null $queryCdSign 收支方向 (选填: 0-收入, 1-支出)
     * @param string|null $expandFields 额外字段 (选填，以|分隔，如: serialNo)
     * @return array
     */
    public function queryDailyDetails(string $bankAcc, ?float $queryAmtBegin = null, ?float $queryAmtEnd = null, ?string $queryCdSign = null, ?string $expandFields = null): array
    {
        $mapData = [
            'bankAcc' => $bankAcc,
        ];

        if ($queryAmtBegin !== null) {
            $mapData['queryAmtBegin'] = number_format($queryAmtBegin, 2, '.', '');
        }

        if ($queryAmtEnd !== null) {
            $mapData['queryAmtEnd'] = number_format($queryAmtEnd, 2, '.', '');
        }

        if ($queryCdSign !== null) {
            $mapData['queryCdSign'] = $queryCdSign;
        }

        if ($expandFields !== null) {
            $mapData['expandFields'] = $expandFields;
        }

        Log::info('Starting daily detail query', [
            'operation' => 'QUERY_DAILY_DETAILS',
            'bank_acc' => $bankAcc,
            'query_amt_begin' => $queryAmtBegin,
            'query_amt_end' => $queryAmtEnd,
            'query_cd_sign' => $queryCdSign,
            'expand_fields' => $expandFields,
        ]);

        $result = $this->client->callApi('DAILY_DETAIL_QUERY', $mapData);

        if ($result['success']) {
            Log::info('Daily detail query completed successfully', [
                'operation' => 'QUERY_DAILY_DETAILS',
                'bank_acc' => $bankAcc,
                'count' => count($result['loop_data']),
                'record_total' => $result['map_data']['recordTotal'] ?? 0,
                'ret_code' => $result['ret_code'],
            ]);
        } else {
            Log::warning('Daily detail query failed', [
                'operation' => 'QUERY_DAILY_DETAILS',
                'bank_acc' => $bankAcc,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);
        }

        return $result;
    }

    /**
     * 历史明细查询 (BY0006)
     *
     * @param string $bankAcc 待查询账号 (必填)
     * @param string $queryDateBegin 查询开始日期 (必填，格式: YYYY-MM-DD)
     * @param string $queryDateEnd 查询结束日期 (必填，格式: YYYY-MM-DD)
     * @param float|null $queryAmtBegin 金额范围起 (选填)
     * @param float|null $queryAmtEnd 金额范围止 (选填)
     * @param string|null $queryCdSign 收支方向 (选填: 0-收入, 1-支出)
     * @param string|null $expandFields 额外字段 (选填，以|分隔，如: serialNo)
     * @return array
     */
    public function queryHistoryDetails(string $bankAcc, string $queryDateBegin, string $queryDateEnd, ?float $queryAmtBegin = null, ?float $queryAmtEnd = null, ?string $queryCdSign = null, ?string $expandFields = null): array
    {
        $mapData = [
            'bankAcc' => $bankAcc,
            'queryDateBegin' => $queryDateBegin,
            'queryDateEnd' => $queryDateEnd,
        ];

        if ($queryAmtBegin !== null) {
            $mapData['queryAmtBegin'] = number_format($queryAmtBegin, 2, '.', '');
        }

        if ($queryAmtEnd !== null) {
            $mapData['queryAmtEnd'] = number_format($queryAmtEnd, 2, '.', '');
        }

        if ($queryCdSign !== null) {
            $mapData['queryCdSign'] = $queryCdSign;
        }

        if ($expandFields !== null) {
            $mapData['expandFields'] = $expandFields;
        }

        Log::info('Starting history detail query', [
            'operation' => 'QUERY_HISTORY_DETAILS',
            'bank_acc' => $bankAcc,
            'query_date_begin' => $queryDateBegin,
            'query_date_end' => $queryDateEnd,
            'query_amt_begin' => $queryAmtBegin,
            'query_amt_end' => $queryAmtEnd,
            'query_cd_sign' => $queryCdSign,
            'expand_fields' => $expandFields,
        ]);

        $result = $this->client->callApi('HISTORY_DETAIL_QUERY', $mapData);

        if ($result['success']) {
            Log::info('History detail query completed successfully', [
                'operation' => 'QUERY_HISTORY_DETAILS',
                'bank_acc' => $bankAcc,
                'query_date_begin' => $queryDateBegin,
                'query_date_end' => $queryDateEnd,
                'count' => count($result['loop_data']),
                'record_total' => $result['map_data']['recordTotal'] ?? 0,
                'ret_code' => $result['ret_code'],
            ]);
        } else {
            Log::warning('History detail query failed', [
                'operation' => 'QUERY_HISTORY_DETAILS',
                'bank_acc' => $bankAcc,
                'query_date_begin' => $queryDateBegin,
                'query_date_end' => $queryDateEnd,
                'ret_code' => $result['ret_code'],
                'error' => $result['ret_msg'],
            ]);
        }

        return $result;
    }

    /**
     * 批处理异常状态检查
     * 根据文档说明，BY0003接口返回retCode=2时仅代表查询失败，不代表付款失败
     *
     * @param array $result
     * @return string pending|success|failed|suspicious
     */
    public function getPaymentStatus(array $result): string
    {
        if (!isset($result['ret_code'])) {
            return 'failed';
        }

        switch ($result['ret_code']) {
            case '0':
                return 'success';
            case '2':
                // 根据文档建议，查询返回2时置为存疑状态
                return 'suspicious';
            default:
                return 'failed';
        }
    }
}
